package com.keyboardr.gamerater;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class Game implements JSONable, Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 8403094090990021559L;
	private static final String TAG = "Game";
	public Player winner, loser;
	private ArrayList<Player> players;
	public boolean draw;
	public Date time;
	private boolean fide;
	private double winRating, loseRating;

	public Game(boolean draw, Player winner, Player loser, Date time,
			boolean fide, ArrayList<Player> players) {
		this.winner = winner;
		winRating = winner.getRating();
		this.loser = loser;
		loseRating = loser.getRating();
		this.fide = fide;
		this.time = time;
		this.draw = draw;
		this.players = players;
	}

	public Game(JSONObject jObject, ArrayList<Player> players) {
		try {
			if (jObject.has("winnerIndex")) {
				winner = players.get(jObject.getInt("winnerIndex"));
				loser = players.get(jObject.getInt("loserIndex"));
			} else {
				Player winnerJSON = new Player(jObject.getJSONObject("winner"));
				Player loserJSON = new Player(jObject.getJSONObject("loser"));
				for (int i = 0; i < players.size()
						&& (winner == null || loser == null); i++) {
					Player player = players.get(i);
					if (player.equals(winnerJSON)) {
						winner = player;
					} else if (player.equals(loserJSON)) {
						loser = player;
					}
				}
				if (winner == null) {
					throw new NullPointerException();// This is to prevent bad
														// data from being saved
				}
				if (loser == null) {
					throw new NullPointerException();// This is to prevent bad
														// data from being saved
				}
			}
			winRating = jObject.getDouble("winRating");
			loseRating = jObject.getDouble("loseRating");
			fide = jObject.getBoolean("fide");
			time = new Date(jObject.getLong("time"));
			draw = jObject.getBoolean("draw");
			this.players = players;
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	public void applyGame() {
		double expectedWinner = 1 / (1 + Math.pow(10,
				(loseRating - winRating) / 400.0));
		double expectedLoser = 1 / (1 + Math.pow(10,
				(winRating - loseRating) / 400.0));
		Log.d(TAG, "Expeced winner: " + expectedWinner + " loser: "
				+ expectedLoser);
		winner.playAGame((winner.getRating() + (winner.getkFactor()
				* ((draw ? 0.5 : 1.0) - expectedWinner) + .5)), fide);
		loser.playAGame((loser.getRating() + (loser.getkFactor()
				* ((draw ? 0.5 : 0.0) - expectedLoser) + .5)), fide);
	}

	public void revert() {
		winner.undoGame(getWinRating(), fide);
		loser.undoGame(getLoseRating(), fide);
	}

	/**
	 * @return the winRating
	 */
	public int getWinRating() {
		return (int) winRating;
	}

	/**
	 * @return the loseRating
	 */
	public int getLoseRating() {
		return (int) loseRating;
	}

	@Override
	public JSONObject toJSON() {
		JSONObject jObject = new JSONObject();
		try {
			// jObject.put("winner", winner.toJSON());
			// jObject.put("loser", loser.toJSON());
			jObject.put("winnerIndex", players.indexOf(winner));
			jObject.put("loserIndex", players.indexOf(loser));
			jObject.put("draw", draw);
			jObject.put("time", time.getTime());
			jObject.put("fide", fide);
			jObject.put("winRating", winRating);
			jObject.put("loseRating", loseRating);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return jObject;
	}

}
